package org.zjvis.datascience.web.controller;

import static org.zjvis.datascience.common.gis.GisUtils.GisUtil.DATASET_SCHEME;
import static org.zjvis.datascience.common.gis.GisUtils.GisUtil.REGEX;
import static org.zjvis.datascience.common.gis.GisUtils.GisUtil.getTabDataJson;
import static org.zjvis.datascience.service.DatasetCategoryService.DEFAULT_GIS_CATEGORY;

import cn.weiguangfu.swagger2.plus.annotation.ApiPlus;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.zjvis.datascience.common.annotation.DashboardAuth;
import org.zjvis.datascience.common.annotation.ProjectRoleAuth;
import org.zjvis.datascience.common.dto.DatasetDTO;
import org.zjvis.datascience.common.dto.DatasetImportResDTO;
import org.zjvis.datascience.common.dto.gis.GisLayersDTO;
import org.zjvis.datascience.common.dto.gis.GisTabsDTO;
import org.zjvis.datascience.common.dto.gis.SliceDTO;
import org.zjvis.datascience.common.dto.user.UserDTO;
import org.zjvis.datascience.common.enums.ProjectRoleAuthEnum;
import org.zjvis.datascience.common.model.ApiResult;
import org.zjvis.datascience.common.model.ApiResultCode;
import org.zjvis.datascience.common.util.JwtUtil;
import org.zjvis.datascience.common.util.SqlUtil;
import org.zjvis.datascience.common.vo.gis.GisDataVO;
import org.zjvis.datascience.common.vo.gis.GisImportVO;
import org.zjvis.datascience.common.vo.gis.GisLayersVO;
import org.zjvis.datascience.common.vo.gis.GisNumericalResVO;
import org.zjvis.datascience.common.vo.gis.GisTabsVO;
import org.zjvis.datascience.service.DashboardService;
import org.zjvis.datascience.service.DatasetCategoryService;
import org.zjvis.datascience.service.TaskService;
import org.zjvis.datascience.service.dataset.DatasetService;
import org.zjvis.datascience.service.gis.GisAnalysisService;
import org.zjvis.datascience.service.gis.GisLayersService;
import org.zjvis.datascience.service.gis.GisService;
import org.zjvis.datascience.service.gis.GisTabsService;

@ApiPlus(value = true)
@RestController
@RequestMapping("/gis")
@Api(tags = "gis", description = "gis接口")
@Validated
public class GisController {
    private final static Logger logger = LoggerFactory.getLogger(GisController.class);

    @Autowired
    private GisService gisService;

    @Autowired
    private GisTabsService gisTabsService;

    @Autowired
    private GisLayersService gisLayersService;

    @Autowired
    private GisAnalysisService gisAnalysisService;

    @Autowired
    private DatasetCategoryService datasetCategoryService;

    @Autowired
    private DatasetService datasetService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private DashboardService dashboardService;


//---------------------------------------------------queryGis数据列表接口-------------------------------------------------

    @Deprecated
    @PostMapping("/queryGisFiles")
    @ApiOperation(value = "Gis文件列表", notes = "gis文件列表")
    public ApiResult<List<GisDataVO>> queryGisFiles(HttpServletRequest request) throws Exception {
        UserDTO user = JwtUtil.getCurrentUserDTO();
        List<GisDataVO> gisDataset = new ArrayList<>();
        Long categoryId = datasetCategoryService.queryCategoryIdByUserIdAndCategoryName(user.getId(), DEFAULT_GIS_CATEGORY);
        gisService.queryGisDataByCategoryId(categoryId).forEach(e -> {
            gisDataset.add(e.gisData());
        });
        return ApiResult.valueOf(gisDataset);
    }

    /**
     * 用户可选是否下载geom字段
     * @param request
     * @param response
     * @param layerId
     * @param name
     * @param format
     * @param geom
     * @param projectId
     */
    @RequestMapping(value = "/downloadTable")
    @ApiOperation(value = "下载数据源表为csv", notes = "下载数据源表为csv")
    public void download(HttpServletRequest request, HttpServletResponse response,
                         @RequestParam("layerId") Long layerId,
                         @RequestParam("name") String name,
                         @RequestParam("format") String format,
                         @RequestParam("geom") Long geom,
                         @RequestParam("projectId") Long projectId) {
        String viewName = gisLayersService.getLayerViewById(layerId);
        List<String> tables = new ArrayList<>();  //为了复用之前的下载接口强行创建list
        tables.add(viewName);
        taskService.downloadLayerToCsv(response, tables, name, geom);
    }


//----------------------------------------------------Tab层接口----------------------------------------------------------

    @PostMapping(value = "/addTabByProjectId")
    @ResponseBody
    @ApiOperation(value = "addTabByProjectId", notes = "增加新图层")
    @Transactional
    public ApiResult<GisTabsVO> addTabByProjectId(HttpServletRequest request,
                                                  @RequestBody
                                                  @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                          JSONObject params) {
        Long projectId = params.getLong("projectId");
        GisTabsDTO gisTabs = gisTabsService.addTabsByProjectId(projectId);
        return ApiResult.valueOf(gisTabs.tab());
    }


    @PostMapping(value = "/deleteTabById")
    @ResponseBody
    @ApiOperation(value = "deleteTabById", notes = "删除画布")
    @Transactional
    public ApiResult<Void> deleteTabById(HttpServletRequest request,
                                         @RequestBody
                                         @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                 JSONObject params) {
        Long tabId = params.getLong("tabId");
        gisTabsService.deleteTabByIds(tabId);
        gisLayersService.deleteLayerByTabId(tabId);
        Long newTabId = dashboardService.queryGisMapping(tabId);
        if (newTabId > -1L) {
            gisTabsService.deleteTabByIds(newTabId);
            gisLayersService.deleteLayerByTabId(newTabId);
        }
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/renameTab")
    @ResponseBody
    @ApiOperation(value = "renameTab", notes = "画布重命名")
    @Transactional
    public ApiResult<GisTabsVO> renameTab(HttpServletRequest request,
                                          @RequestBody
                                          @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                  JSONObject params) {
        GisTabsDTO tabDTO = gisTabsService.queryTabInfoById(params.getLong("tabId"));
        tabDTO.setTabName(params.getString("tabName"));
        gisTabsService.update(tabDTO);
        return ApiResult.valueOf(tabDTO.tab());
    }

    @PostMapping(value = "/queryTabInfoById")
    @ResponseBody
    @ApiOperation(value = "queryTabInfoById", notes = "查询画布信息")
    @Transactional
    public ApiResult<GisTabsVO> queryByTabId(HttpServletRequest request,
        @RequestBody @DashboardAuth
        @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
            JSONObject params) {
        Long id = params.getLong("id");
        GisTabsDTO tab = gisTabsService.queryTabInfoById(id);
        return ApiResult.valueOf(tab.tab());
    }

    @PostMapping(value = "/queryTabsByProjectId")
    @ResponseBody
    @ApiOperation(value = "queryTabsByProjectId", notes = "通过projectId查询画布列表信息")
    @Transactional
    public ApiResult<List<GisTabsVO>> queryTabsByProjectId(HttpServletRequest request,
                                                           @RequestBody
                                                           @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                                   JSONObject params) {
        List<GisTabsVO> tabs = new ArrayList<>();
        Long projectId = params.getLong("projectId");
        gisTabsService.queryTabsByProjectId(projectId).forEach(e -> {
            if (e.getDataJson() == null) {
                e.setDataJson(getTabDataJson().toJSONString());
            }
            tabs.add(e.tab());
        });
        return ApiResult.valueOf(tabs);
    }

    @PostMapping(value = "/copyTab")
    @ResponseBody
    @ApiOperation(value = "copyTab", notes = "复制画布")
    @Transactional
    public ApiResult<GisTabsVO> copyTab(HttpServletRequest request,
                                        @RequestBody
                                        @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                JSONObject params) {
        Long projectId = params.getLong("projectId");
        Long tabId = params.getLong("tabId");
        //复制画布并改名
        GisTabsDTO copyTabDTO = gisTabsService.copyTab(tabId, projectId, false);
        //复制画布中的图层
        Long copyTabId = copyTabDTO.getId();
        gisLayersService.copyLayers(tabId, copyTabId);
        return ApiResult.valueOf(copyTabDTO.tab());
    }


//---------------------------------------------------Layers层接口--------------------------------------------------------

    @PostMapping("/queryLayersByTabId")
    @ApiOperation(value = "通过tabId返回layers层信息", notes = "通过tabId返回layers层信息")
    public ApiResult<List<GisLayersVO>> queryLayersByTabId(HttpServletRequest request,
                                                           @RequestBody @DashboardAuth
//                                                           @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                                   JSONObject params) {
        Long tabId = params.getLong("tabId");
        List<GisLayersVO> layers = new ArrayList<>();
        gisLayersService.queryLayersByTabId(tabId).forEach(e -> {
            layers.add(e.layer());
        });
        return ApiResult.valueOf(layers);
    }

    @PostMapping(value = "/addLayer")
    @ResponseBody
    @ApiOperation(value = "addLayer", notes = "增加新图层")
    @Transactional
    public ApiResult<List<GisLayersVO>> addLayer(HttpServletRequest request,
                                                 @RequestBody
                                                 @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                         JSONObject params) {
        Long projectId = params.getLong("projectId");
        Long tabId = params.getLong("tabId");
        List<Long> datasetIds = params.getJSONArray("datasetIds").toJavaList(Long.class);
        UserDTO user = JwtUtil.getCurrentUserDTO();
        Long userId = user.getId();
        gisLayersService.updateLayerOrder(userId, tabId, datasetIds);   //新增图层自动放到首位，其他图层order自动累加
        List<GisLayersVO> newLayers = new ArrayList<>();
        int i = 1;
        for (Long datasetId : datasetIds) {
            DatasetDTO datasetDTO = datasetService.queryById(datasetId);
            JSONObject jsonObject = JSONObject.parseObject(datasetDTO.getDataJson());
            String srid = jsonObject.getString("srid");
            String proj4Text = null;
            if (Objects.nonNull(jsonObject.getJSONObject("gisConfig"))) {
                proj4Text = jsonObject.getJSONObject("gisConfig").getString("proj4Text");
            }
//            String srid = gisAnalysisService.getSRID(datasetDTO.gisData().getTbName());
            String tbName = DATASET_SCHEME + datasetDTO.gisData().getTbName();
            String datasetName = datasetDTO.gisData().getDatasetName();
            String type = gisAnalysisService.queryGeomType(tbName);
            GisLayersDTO gisLayer = gisLayersService.addLoadLayersByTabId(projectId, userId, tabId, tbName, datasetName, type);
            Long layerId = gisLayer.getId();

            //生成geom_4326列, 避免每次查询,均执行坐标转换操作
            if(!datasetService.isAddGeom4326(tbName)) {
                String originGeomType = gisAnalysisService.queryOriginGeomType(tbName);
                gisAnalysisService.addAndUpdateGeom4326Column(tbName, originGeomType, srid, proj4Text);
                datasetService.addGeom4326Tag(tbName);
            }

            String viewTable = gisAnalysisService.createView(tbName, projectId, tabId, layerId);
            gisLayer.setViewTable(viewTable);
            //一次导入多个图层后排序
            gisLayer.setLayerOrder((long) i);
            gisLayersService.update(gisLayer);
            GisLayersDTO newLayerDTO = gisLayersService.queryLayerInfoById(gisLayer.getId());
            newLayers.add(newLayerDTO.layer());
            i = i + 1;
        }
        return ApiResult.valueOf(newLayers);
    }

    @PostMapping(value = "/deleteLayerById")
    @ResponseBody
    @ApiOperation(value = "deleteLayerById", notes = "通过layerId删除图层")
    @Transactional
    public ApiResult<Void> deleteLayerById(HttpServletRequest request,
                                           @RequestBody
                                           @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                   JSONObject params) {
        List<Long> layerIds = params.getJSONArray("layerIds").toJavaList(Long.class);
        gisLayersService.deleteLayers(layerIds);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/resetOrder")
    @ResponseBody
    @ApiOperation(value = "resetOrder", notes = "设置图层order")
    @Transactional
    public ApiResult<List<GisLayersVO>> resetOrder(HttpServletRequest request,
                                                   @RequestBody
                                                   @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                           JSONObject params) {
        Long tabId = params.getLong("tabId");
        List<Long> orders = params.getJSONArray("orders").toJavaList(Long.class);
        gisLayersService.updateLoadDataOrder(orders);
        List<GisLayersVO> layers = new ArrayList<>();
        gisLayersService.queryLayersByTabId(tabId).forEach(e -> {
            layers.add(e.layer());
        });
        return ApiResult.valueOf(layers);
    }

    @PostMapping("/plotLayerByGeoJson")
    @ApiOperation(value = "plotLayer", notes = "转换成geojson渲染图层")
    public ApiResult<JSONObject> plotLayerByGeoJson(HttpServletRequest request,
                                                    @RequestBody @DashboardAuth
                                                    //@ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                            JSONObject params) {
        Long layerId = params.getLong("layerId");
        String viewName = gisLayersService.getLayerViewById(layerId);
        GisLayersDTO gisLayer = gisLayersService.queryLayerInfoById(layerId);
        String type = gisLayer.getType();
        JSONObject geojson = new JSONObject();
        if (params.containsKey("kGraph") && params.getBoolean("kGraph")){
            if (params.containsKey("public") || params.containsKey("publish")){
                if (params.containsKey("dynamicFilters")){
                    geojson = gisAnalysisService.geojsonConverterKG_Publish(viewName, params.getLong("projectId"),type,params.getJSONObject("dynamicFilters"),layerId);
                }else{
                    geojson = gisAnalysisService.geojsonConverterKG_Publish(viewName, params.getLong("projectId"),type, null, layerId);
                }
            }else{
                geojson = gisAnalysisService.geojsonConverterKG(viewName, params.getLong("projectId"),type,layerId);
            }
        }
        else {
//            geojson = gisAnalysisService.geojsonConverter(viewName);
            geojson = gisAnalysisService.geoJsonConverter(viewName, gisLayer.getSourceTable());
        }

        GisLayersDTO layersDTO = gisLayersService.queryLayerInfoById(params.getLong("layerId"));
        String layerType = layersDTO.getType();
        JSONObject res = gisAnalysisService.createGeojson(layerType, geojson, null);
        return ApiResult.valueOf(ApiResultCode.SUCCESS, res);
    }

    @PostMapping("/plotLayerBySliceGeoJson")
    @ApiOperation(value = "plotLayerBySliceGeoJson", notes = "分片渲染图层")
    public ApiResult<JSONObject> plotLayerBySliceGeoJson(HttpServletRequest request,
            @RequestBody @DashboardAuth JSONObject params) {
        SliceDTO requestSliceDTO = SliceDTO.builder()
                .index(params.getInteger("sliceIndex"))
                .offset(params.getLong("sliceOffset"))
                .pageSize(params.getLong("slicePageSize"))
                .build();

        GisLayersDTO layerDTO = gisLayersService.queryLayerInfoById(params.getLong("layerId"));
        String sourceTable = layerDTO.getSourceTable();
        String viewTable = layerDTO.getViewTable();
        String layerType = layerDTO.getType();

        //第一次, 需返回分片数据
        List<SliceDTO> sliceDTOS = null;
        JSONArray sliceJson = null;
        if(requestSliceDTO.getIndex() == 0) {
            sliceDTOS = gisAnalysisService.getSliceDTO(sourceTable, params.getLong("sliceSize"), null);
            //填充完整第一次请求的分片参数
            requestSliceDTO.setOffset(sliceDTOS.get(0).getOffset());
            requestSliceDTO.setPageSize(sliceDTOS.get(0).getPageSize());
            sliceJson = JSONArray.parseArray(JSON.toJSONString(sliceDTOS));
        }

        //多线程, 预加载功能
        gisAnalysisService.preloadSliceGeoJsonSliceData(viewTable, sourceTable, requestSliceDTO,
                params.getLong("sliceSize"), null);

        JSONObject geoJson = gisAnalysisService.geoJsonConverterSlice(viewTable, requestSliceDTO);

        JSONObject res = gisAnalysisService.createGeojson(layerType, geoJson, null);
        if(Objects.nonNull(sliceJson)) {
            res.put("slicejson", sliceJson);
        }
        return ApiResult.valueOf(ApiResultCode.SUCCESS, res);
    }



    @PostMapping("/queryLayerInfoById")
    @ApiOperation(value = "queryLayerInfoById", notes = "查询当前图层信息")
    public ApiResult<GisLayersVO> queryLayerInfoById(HttpServletRequest request,
                                                     @RequestBody
                                                     @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                             JSONObject params) {
        GisLayersDTO layersDTO = gisLayersService.queryLayerInfoById(params.getLong("layerId"));
        return ApiResult.valueOf(layersDTO.layer());
    }


    @PostMapping("/saveInfo")
    @ApiOperation(value = "saveInfo", notes = "设置标记")
    public ApiResult<Void> saveInfo(HttpServletRequest request, @RequestBody JSONObject params) {
        Long tabId = params.getLong("tabId");
        JSONObject tabInfo = params.getJSONObject("tabInfo");
        JSONArray layers = params.getJSONArray("layers");
        String tabName = params.getString("tabName");
        gisLayersService.saveInfo(tabId, tabInfo, layers,tabName);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }


    //---------------------------------------------------数理分析接口-----------------------------------------------------
    @PostMapping("/calculateAll")
    @ApiOperation(value = "calculateAll", notes = "计算全局面积/周长/长度")
    public ApiResult<GisLayersVO> addArea(HttpServletRequest request,
                                          @RequestBody
                                          @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                  JSONObject params) {
        Long layerId = params.getLong("layerId");
        Long projectId = params.getLong("projectId");
        long tabId = params.getLong("tabId");
        String unit = params.getString("unit");
        String colName = params.getString("columnName");
        String method = params.getString("method");
        Integer precision = params.getInteger("precision");
        String viewName = gisLayersService.getLayerViewById(layerId);
        String sourceTbName = gisLayersService.queryTbNameByLayerId(layerId);
        String columnName = colName.replace(" ", "");
        //检查字段名长度
        if (columnName.length() > 15) {
            return ApiResult.valueOf(ApiResultCode.GIS_COL_NAME_LENGTH_ERROR);
        }
        //检验重名问题
        if (columnName.matches(REGEX) == true || StringUtils.isBlank(columnName) || gisService.isStartWithNumber(columnName) == true) {
            return ApiResult.valueOf(ApiResultCode.GIS_ADD_NEW_COL_NAME_ERROR);
        }

        String checkedColName = gisService.checkColName(sourceTbName, columnName);
        int checkResult = gisService.checkName(viewName, sourceTbName, checkedColName);
        if (checkResult == 0) {
            return ApiResult.valueOf(ApiResultCode.GIS_ADD_NEW_COL_ERROR);
        }
        String newViewName = gisAnalysisService.getNewView(viewName, projectId, tabId, layerId, checkedColName, method, unit, precision);
        GisLayersDTO layersDTO = gisLayersService.queryLayerInfoById(params.getLong("layerId"));
        layersDTO.setViewTable(newViewName);
        gisLayersService.update(layersDTO);
//        不计算全局面积/周长/长度
//        Float totalResult = gisAnalysisService.addAll(newViewName, checkedColName, unit);
//        BigDecimal calRes = new BigDecimal(totalResult);
        return ApiResult.valueOf(layersDTO.layer());
    }

    @PostMapping("/previewCentroid")
    @ApiOperation(value = "previewCentroid", notes = "预览几何中心")
    public ApiResult<JSONObject> previewCentroid(HttpServletRequest request,
                                                 @RequestBody
                                                 @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                         JSONObject params) {
        Long layerId = params.getLong("layerId");
        Long projectId = params.getLong("projectId");
        Long tabId = params.getLong("tabId");
        GisLayersDTO gisLayersDTO = gisLayersService.queryLayerInfoById(layerId);
        String newView = gisAnalysisService.previewCentoridData(gisLayersDTO.getViewTable(), projectId, tabId, layerId);
        JSONObject geoJson = gisAnalysisService.geoJsonConverter(newView, gisLayersDTO.getSourceTable());
        String type = gisAnalysisService.queryNewGeomType(newView);
        JSONObject res = gisAnalysisService.createGeojson(type, geoJson, null);
        return ApiResult.valueOf(ApiResultCode.SUCCESS, res);
    }

    @PostMapping("/saveCentroidLayer")
    @ApiOperation(value = "saveCentroidLayer", notes = "保存几何中心图层")
    public ApiResult<List<GisLayersVO>> saveCentroidLayer(HttpServletRequest request,
                                                          @RequestBody
                                                          @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                                  JSONObject params) {
        Long layerId = params.getLong("layerId");
        Long projectId = params.getLong("projectId");
        Long tabId = params.getLong("tabId");
        String setLayerName = params.getString("setLayerName");
        UserDTO user = JwtUtil.getCurrentUserDTO();
        Long userId = user.getId();
        if (setLayerName == "") {
            return ApiResult.valueOf(ApiResultCode.GIS_ADD_NEW_COL_NAME_ERROR);
        }
        List<Long> Ids = gisLayersService.queryLayerIds(userId, tabId);
        gisLayersService.updateAnalysisOrder(Ids, userId, tabId);
        String viewName = gisLayersService.getLayerViewById(layerId);
        String sourceTbName = gisLayersService.queryTbNameByLayerId(layerId);
        String newView = gisAnalysisService.previewCentoridData(viewName, projectId, tabId, layerId);
        String type = gisAnalysisService.queryNewGeomType(newView);
        GisLayersDTO gisLayers = gisLayersService.addAnalysisLayer(projectId, userId, tabId, sourceTbName, setLayerName, type);
        gisLayers.setViewTable(newView);
        gisLayersService.update(gisLayers);
        List<GisLayersVO> layers = new ArrayList<>();
        gisLayersService.queryLayersByTabId(tabId).forEach(e -> {
            layers.add(e.layer());
        });
        return ApiResult.valueOf(layers);
    }


    @PostMapping("/previewBuffer")
    @ApiOperation(value = "previewBuffer", notes = "预览缓冲区绘制")
    public ApiResult<JSONObject> previewBuffer(HttpServletRequest request,
                                               @RequestBody
                                               @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                       JSONObject params) {
        Long layerId = params.getLong("layerId");
        Long projectId = params.getLong("projectId");
        Long tabId = params.getLong("tabId");
        double radius = params.getDouble("radius");
        String unit = params.getString("unit");
        String range = params.getString("range");
        String bufferType = params.getString("bufferType");
        GisLayersDTO layersDTO = gisLayersService.queryLayerInfoById(layerId);
        String newView = gisAnalysisService.previewBufferData(layersDTO.getViewTable(), projectId, tabId, layerId, radius, unit);
        JSONObject geoJson = gisAnalysisService.geoJsonConverter(newView, layersDTO.getSourceTable());
        String type = gisAnalysisService.queryNewGeomType(newView);
        JSONObject res = gisAnalysisService.createGeojson(type, geoJson, null);
        return ApiResult.valueOf(ApiResultCode.SUCCESS, res);
    }

    @PostMapping("/saveBufferLayers")
    @ApiOperation(value = "saveBufferLayers", notes = "保存缓冲区绘制")
    public ApiResult<List<GisLayersVO>> saveBufferLayers(HttpServletRequest request,
                                                         @RequestBody
                                                         @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                                 JSONObject params) {
        Long layerId = params.getLong("layerId");
        Long projectId = params.getLong("projectId");
        Long tabId = params.getLong("tabId");
        String setLayerName = params.getString("setLayerName");
        double radius = params.getDouble("radius");
        String unit = params.getString("unit");
        String range = params.getString("range");
        String bufferType = params.getString("bufferType");
        UserDTO user = JwtUtil.getCurrentUserDTO();
        Long userId = user.getId();
        if (StringUtils.isEmpty(setLayerName)) {
            return ApiResult.valueOf(ApiResultCode.GIS_ADD_NEW_COL_NAME_ERROR);
        }
        if (radius < 0) {
            return ApiResult.valueOf(ApiResultCode.GIS_BUFFER_RADIUS_ERROR);
        }
        List<Long> Ids = gisLayersService.queryLayerIds(userId, tabId);
        gisLayersService.updateAnalysisOrder(Ids, userId, tabId);
        String viewName = gisLayersService.getLayerViewById(layerId);
        String newView = gisAnalysisService.previewBufferData(viewName, projectId, tabId, layerId, radius, unit);
        String sourceTbName = gisLayersService.queryTbNameByLayerId(layerId);
        String type = gisAnalysisService.queryNewGeomType(newView);
        GisLayersDTO gisLayers = gisLayersService.addAnalysisLayer(projectId, userId, tabId, sourceTbName, setLayerName, type);
        gisLayers.setViewTable(newView);
        gisLayersService.update(gisLayers);
        List<GisLayersVO> layers = new ArrayList<>();
        gisLayersService.queryLayersByTabId(tabId).forEach(e -> {
            layers.add(e.layer());
        });
        return ApiResult.valueOf(layers);
    }

    @PostMapping("/getColTypes")
    @ApiOperation(value = "getColTypes", notes = "返回view表中的数值类型的列")
    public ApiResult<JSONObject> getColTypes(HttpServletRequest request,
                                                   @RequestBody
                                                   @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                           JSONObject params) {
        Long layerId = params.getLong("layerId");
        String viewName = gisLayersService.getLayerViewById(layerId);
        JSONObject res = gisAnalysisService.getColTypes(viewName);
        return ApiResult.valueOf(res);
    }

    @PostMapping("/statistics")
    @ApiOperation(value = "statistics", notes = "返回view表中的数值类型的列的最大值、最小值、均值、差值和去重计数")
    public ApiResult<GisNumericalResVO> statistics(HttpServletRequest request,
                                                        @RequestBody
                                                        @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                                JSONObject params) {
        Long layerId = params.getLong("layerId");
        String col = params.getString("col");
        String filterSql = "";
        if (params.getString("filterCol") != null) {
            String filterCol = params.getString("filterCol");
            JSONArray filterVals = params.getJSONArray("filterVals");
            List<String> filters = new ArrayList<>();
            for (Object val : filterVals) {
                filters.add(String.format("\"%s\" = '%s'", filterCol, val));
            }
            filterSql = String.format(" where %s", Joiner.on(" or ").join(filters));
        }
        String viewName = gisLayersService.getLayerViewById(layerId);
        Integer precision = params.getInteger("precision");
        GisNumericalResVO res = null;
        if (params.getString("dateUnit") != null){
            String dateUnit = params.getString("dateUnit");
            res = gisAnalysisService.statistics(viewName, col, filterSql, precision, true, dateUnit);
        } else {
            col = SqlUtil.formatPGSqlColName(col);
            res = gisAnalysisService
                .statistics(viewName, col, filterSql, precision, false, null);
        }
        return ApiResult.valueOf(res);
    }


    @PostMapping("/nearSearch")
    @ApiOperation(value = "nearSearch", notes = "近邻查询后生成新图层")
    public ApiResult<List<GisLayersVO>> nearSearch(HttpServletRequest request,
                                                   @RequestBody
                                                   @ProjectRoleAuth(role = ProjectRoleAuthEnum.CREATOR)
                                                           JSONObject params) {
        Long projectId = params.getLong("projectId");
        Long tabId = params.getLong("tabId");
        Long currentLayerId = params.getLong("currentLayerId");
        Long targetLayerId = params.getLong("targetLayerId");
        Long elementId = params.getLong("elementId");
        Integer neighbors = params.getInteger("neighbors");
        String setLayerName = params.getString("setLayerName");
        UserDTO user = JwtUtil.getCurrentUserDTO();
        Long userId = user.getId();
        String currentViewName = gisLayersService.getLayerViewById(currentLayerId);
        String targetViewName = gisLayersService.getLayerViewById(targetLayerId);
        //判断查找要素个数是否大于目标图层的要素总个数
        Integer countElements = gisAnalysisService.getNumberOfElements(targetViewName);
        if (neighbors >= countElements) {
            return ApiResult.valueOf(ApiResultCode.GIS_OVER_TOTAL_ELEMENTS_ERROR);
        }
        //提前把当前画布的layer的order全部后移一位，然后设置新layer的order为1
        List<Long> Ids = gisLayersService.queryLayerIds(userId, tabId);
        gisLayersService.updateAnalysisOrder(Ids, userId, tabId);
        //拿出来新的view名并执行creat sql
        String nearLayerView = gisAnalysisService.getNearElementsLayer(projectId, tabId, currentLayerId, currentViewName, targetViewName, elementId, neighbors);
        //拿出新view的原表名
        String sourceTbName = gisLayersService.queryTbNameByLayerId(currentLayerId);
        //拿出新view的类型
        String type = gisAnalysisService.queryNewGeomType(nearLayerView);
        //添加新layer到数据库中
        GisLayersDTO gisLayers = gisLayersService.addAnalysisLayer(projectId, userId, tabId, sourceTbName, setLayerName, type);
        gisLayers.setViewTable(nearLayerView);
        gisLayersService.update(gisLayers);
        List<GisLayersVO> layers = new ArrayList<>();
        gisLayersService.queryLayersByTabId(tabId).forEach(e -> {
            layers.add(e.layer());
        });
        return ApiResult.valueOf(layers);
    }

    @PostMapping("/pointToLine")
    @ApiOperation(value = "点转线", notes = "点转线")
    public ApiResult<List<GisLayersVO>> pointToLine(HttpServletRequest request, @RequestBody JSONObject params) {
        String col = params.getOrDefault("col", "").toString();
        String orderCol = params.getString("orderCol");
        String source = params.getString("table");
        String layerName = params.getString("layerName");
        Long projectId = params.getLong("projectId");
        Long currentLayerId = params.getLong("currentLayerId");
        Long tabId = params.getLong("tabId");
        boolean hasArrow = params.getBoolean("hasArrow");
        List<GisLayersVO> layers = gisAnalysisService.pointToLine(col, orderCol, source, layerName, projectId, currentLayerId, tabId, hasArrow);
        return ApiResult.valueOf(layers);
    }


//-------------------------------------------------上传文件接口-----------------------------------------------------------

    @PostMapping("/uploadShapeFile")
    @ApiOperation(value = "文件上传", notes = "文件上传")
    public ApiResult<JSONObject> uploadFiles(
            @Valid @NotNull @RequestParam("file") MultipartFile file, String batch) {
        String name = Objects.requireNonNull(file.getOriginalFilename()).toLowerCase();
        if (!name.endsWith(".shp") && !name.endsWith(".dbf") && !name.endsWith(".shx")) {
            logger.warn("API /gis/uploadShapeFile failed, since {}", ApiResultCode.GIS_SHP_FILE_SUPPORT.getMessage());
            return ApiResult.valueOf(ApiResultCode.GIS_SHP_FILE_SUPPORT);
        }
        if (file.getSize() == 0) {
            logger.warn("API /gis/uploadShapeFile failed, since uploading file's size is 0");
            return ApiResult.valueOf(ApiResultCode.CONTENT_ERROR);
        }
        if (StringUtils.isBlank(batch)) {
            batch = JwtUtil.getCurrentUserId() + "-" + System.currentTimeMillis();
        }
        JSONObject res = gisService.uploadShapeFile(file, name, batch);
        return ApiResult.valueOf(ApiResultCode.SUCCESS, res);
    }

    @PostMapping("/uploadShapeFiles")
    @ApiOperation(value = "文件上传", notes = "文件上传")
    public ApiResult<JSONObject> uploadFiles(
            @Valid @NotNull @RequestParam("files") MultipartFile[] files, String batch) {
        if (files.length > 4) {
            logger.warn("API /gis/uploadShapeFiles failed, since {}", ApiResultCode.GIS_SHP_FILE_UPLOAD_BATCH.getMessage());
            return ApiResult.valueOf(ApiResultCode.GIS_SHP_FILE_UPLOAD_BATCH);
        }
        JSONObject res = gisService.getSRID(files);
        res.put("uploadResult", gisService.uploadShapeFiles(files, batch));
        return ApiResult.valueOf(ApiResultCode.SUCCESS, res);
    }

    @PostMapping("/importData")
    @ApiOperation(value = "文件写入数据库", notes = "文件写入数据库")
    public ApiResult<DatasetImportResDTO> importData(@Valid @RequestBody GisImportVO vo) {
        if (gisService.checkMultipleFile(vo.getFiles()) == 1) {
            return ApiResult.valueOf(ApiResultCode.GIS_MULTIPLE_FILES);
        }
        if (gisService.checkSameFile(vo.getFiles()) == 1) {
            return ApiResult.valueOf(ApiResultCode.GIS_NOT_SAME_FILES);
        }
        return ApiResult.valueOf(gisService.importData(vo));
    }

}
